#ifndef _REP_HPP_
#define _REP_HPP_
#include <sys/types.h>
#include <utility>
#include <list>

//Number of different sizes of objects.  Determines the maximum object
//size.
#define NUMLISTS 32
//Past 2^DMMIB, we only allocate memory in chunks of size 2^DMMIB.
//Before that, we double the amount of memory we allocate on each
//allocation. (by default) (this should be settable on the command
//line later).
#define DEFAULT_MAX_MEM_INC_BITS 16

using namespace std;

namespace rep{
  
  /**
   * An object or frame is just an array of slots.  The tag of a slot
   * determines what type of data it has; after the tag is the data
   * element, which can directly store a 32-bit value, or a pointer to
   * another object.
   *
   * The first slot in an object/frame is used for bookeeping.  When
   * the object is in a freelist, the "obj" field of the first slot is
   * used as a "next" pointer.  
   */

  class Slot{
  public:
    uint32_t tag; // this is used as a type tag
    union {
      void* pointer;      
      int32_t i;
      uint32_t u;
      Slot* obj;
    };
  };

  class FrameAllocator{
  public:
    static void init(unsigned bits);
    static void done();
    static Slot* getFrame(unsigned size);
    //this one returns null if there is not enough memory allocated or
    //we need to GC or something.
    static Slot* getFrameWeak(unsigned size); 
    static void garbageCollect();
    ~FrameAllocator();
  protected:
    static const uint32_t sizetable[];
    //Protect these methods to make FrameAllocator a singleton.
    FrameAllocator();
    FrameAllocator(unsigned bits);
    FrameAllocator(const FrameAllocator&);
    FrameAllocator& operator=(const FrameAllocator&);

    Slot* pop(unsigned listnum);
    void push(unsigned listnum, Slot* freed);

    int next_present(unsigned bits);

    int refill(unsigned listnum);
    void alloc_more();
    static FrameAllocator* fa;
  private:
    Slot* freelists[NUMLISTS];
    unsigned long total_avail;
    unsigned long total_alloc;
    unsigned bits_per_alloc;
    unsigned max_bits_per_alloc;
    list< pair<Slot*, unsigned>* > allocated_blocks;
  };

}

#endif //_REP_HPP_
